//
//  GYPeriphreal.m
//  LockManagement
//
//  Created by apple on 2018/7/30.
//  Copyright © 2018年 yunjiazhineng. All rights reserved.
//

#import "GYPeriphreal.h"
#import "GYCenterManager.h"
#import "GYService.h"
#import "GYCharacteristic.h"

@interface GYPeriphreal()<CBPeripheralDelegate>
{
    __block BOOL     _isReconnectDevice ;//用来处理发起连接时的参数问题。因为没调用连接一次，只能返回一次连接结果。
}

/** 连接超时时间(默认5秒) */
@property (nonatomic, assign) NSTimeInterval connectTimeOut;

/** 读取RSSI值的block回调 */
@property (nonatomic, strong) blueManagerReadRSSIBlock blueManagerReadRSSICallBack;

/** 连接设备的条件 */
@property (nonatomic, strong) NSDictionary *connectOptions;

/** nstimer  连接设备超时定时器 */
@property (nonatomic, strong) NSTimer *deviceTimeOutTimer;

/** 设备发现服务回调数组 */
@property (nonatomic, strong) NSMutableArray<blueManagerSearchDeviceServiceBlock> *findServiceCallBackArray;

/** 中心manage */
@property (nonatomic, strong, readwrite) GYCenterManager *centerManager;
@end

@implementation GYPeriphreal

- (void)dealloc {
    NSLog(@"%@====设备已销毁====%@",self.name,self.identifierString);
    self.periphreal.delegate = nil;
    self.periphreal = nil;
}

- (instancetype)initWithPeriphreal:(CBPeripheral *)periphreal {
    return [self initWithPeriphreal:periphreal central:self.centerManager];
}

- (instancetype)initWithPeriphreal:(CBPeripheral *)periphreal central:(GYCenterManager *)manager {
    if (self = [super init]) {
        self.centerManager = manager;
        self.periphreal = periphreal;
        self.periphreal.delegate = self;
        
        self.connectTimeOut = 5;
        kWeakSelf(self)
        
        //
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakself performSelector:@selector(devicenoFoundTimeOut) withObject:nil afterDelay:5.0f];
        });
    }
    return self;
}

#warning ?????????????
//设置设备被扫描到的次数
- (void)setDeviceScanCount:(NSUInteger)deviceScanCount {
    _deviceScanCount = deviceScanCount;
    
    kWeakSelf(self);
    dispatch_async(dispatch_get_main_queue(), ^{
        [NSObject cancelPreviousPerformRequestsWithTarget:weakself selector:@selector(devicenoFoundTimeOut) object:nil];
        
        [weakself performSelector:@selector(devicenoFoundTimeOut) withObject:nil afterDelay:5.0f];
    });
}


- (void)devicenoFoundTimeOut {
    [self.centerManager foundDeviceTimeout:self];
}

#pragma mark -- get方法

- (NSUUID *)identifier {
    return self.periphreal.identifier;
}

- (NSString *)identifierString {
    return self.periphreal.identifier.UUIDString;
}

- (CBPeripheralState)state {
    return self.periphreal.state;
}

- (NSString *)name {
    NSString *locaName = [self.advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
    if (locaName == nil || locaName.length == 0) {
        locaName = @"无名称";
    }
    
    return locaName;
}

- (NSNumber *)RSSI {
    if (_RSSI.intValue == 127) {
        return [NSNumber new];
    }
    
    return _RSSI;
}

- (BOOL)isConnected {
    BOOL connect = NO;
    //判断外围设备的链接状态
    if (self.periphreal.state == CBPeripheralStateConnected) {
        connect = YES;
    }
    
    return connect;
}


#pragma mark -- connect 链接方法

- (void)connectDeviceWithBlcok:(blueManagerConnectDeviceBlock)callBack {
    [self connectDeviceWithBlcok:callBack];
}

- (void)connectDeviceWithTimeOut:(NSTimeInterval)timeOut callBack:(blueManagerConnectDeviceBlock)callBack {
    [self connectDeviceWithTimeOut:timeOut options:nil callBack:callBack];
}

- (void)connectDeviceWithTimeOut:(NSTimeInterval)timeOut options:(NSDictionary *)options callBack:(blueManagerConnectDeviceBlock)callBack {
    
    //然后赋值
    NSAssert(callBack, @"you should handle connect device callback !");
    
    //赋值链接设备的回到block
    if (callBack) {
        self.blueManagerConnectDeviceCallBack = [callBack copy];
    }
    
    self.connectTimeOut = timeOut;
    self.connectOptions = options;
    _isReconnectDevice = YES;  //正在链接设备
    
    //判断如果该设备是连接状态的要断开设备连接 重新连接
    if (self.periphreal.state == CBPeripheralStateConnected ) {
        NSLog(@"attention ! the device is readly connected !" );
        [self disConnectDevice];
    }
    
    NSLog(@"begin connect device");
    [self.centerManager.centerMnaager connectPeripheral:self.periphreal options:options];
    
    //如果设定的时间内系统没有返回连接的结果,直接返回错误信息
    kWeakSelf(self)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeOut * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //判断是不是在连接设备的状态
        if (!_isReconnectDevice) {
            return ;
        }
        
        NSError *error = [NSError errorWithDomain:@"connect device timeout ~~" code:-101 userInfo:nil];
        if (self.blueManagerConnectDeviceCallBack) {
            self.blueManagerConnectDeviceCallBack(self, error, deviceConntTypeFiledTimeOut);
        }
        
        _isReconnectDevice = NO;
        
        [weakself disConnectDevice];
    });
}

#pragma mark -- discover service

- (void)discoverAllDeviceServiceWithCallBack:(blueManagerSearchDeviceServiceBlock)callBack {
    [self discoverDeviceServiceWithUUIDArray:nil callback:callBack];
}

- (void)discoverDeviceServiceWithUUIDArray:(NSArray<CBUUID *> *)uuidArray callback:(blueManagerSearchDeviceServiceBlock)callback {
    NSAssert(callback, @"you should deal the callback");
    
    //把这个服务数据存起来
    if (callback) {
        [self.findServiceCallBackArray addObject:callback];
    }
    
    BOOL isAllUUIDExtied = uuidArray > 0; //需要查找的UUID是否都存在
    
    for (CBUUID *tempUUID in uuidArray) {
        
        BOOL isExtedUUID = NO;  //这里需要查找单个uuid是否存在
        for (GYService *tempService in self.serviceArray) {
            if ([tempService.UUID isEqual:tempUUID]) {
                isExtedUUID = YES;
                break;
            }
            
            if (!isExtedUUID) {
                isAllUUIDExtied = NO;
                break;
            }
        }
    }
    
    if (isAllUUIDExtied) {
        if (self.findServiceCallBackArray.count > 0) {
            blueManagerSearchDeviceServiceBlock serviceCallBack = self.findServiceCallBackArray.firstObject;
            serviceCallBack(self,self.serviceArray,nil);
            serviceCallBack = nil;
            
            [self.findServiceCallBackArray removeObjectAtIndex:0];
        }
    }else {
        NSLog(@"寻找设备设备上的服务  ====%@",self.periphreal.identifier.UUIDString);
        
        //调用设备开始发现服务----
        [self.periphreal discoverServices:uuidArray];
    }
    
}

#pragma mark -- 其他方法

//自动断开  重连
- (void)reconnectDevice {
    _isReconnectDevice = YES;
    [self connectDeviceWithTimeOut:self.connectTimeOut options:self.connectOptions callBack:self.blueManagerConnectDeviceCallBack];
}

- (void)resetDeviceScanCount {
    self.deviceScanCount = -1;
}

//读取RSSI值回调
- (void)readDeviceRSSIWithCallback:(blueManagerReadRSSIBlock)callback {
    NSAssert(callback, @"you should deal the callback");
    
    if (callback) {
        self.blueManagerConnectDeviceCallBack = [callback copy];
    }
    
    NSLog(@"读取设备的rssi值=======%@",self.periphreal.identifier.UUIDString);
    [self.periphreal readRSSI];
}

//搜寻到服务
- (GYService *)searchServiceWithService:(CBService *)service {
    GYService *tempService = nil;
    for (GYService *temps in self.serviceArray) {
        if ([temps.UUID isEqual:service.UUID]) {
            tempService = temps;
            break;
        }
    }
    
    return tempService;
}

//断开连接设备
- (void)disConnectDevice {
    if (self.state == CBPeripheralStateConnected) {
        NSLog(@"断开设备连接  ====%@",self.periphreal.identifier.UUIDString);
        [self.centerManager.centerMnaager cancelPeripheralConnection:self.periphreal];
    }
    
    [NSObject cancelPreviousPerformRequestsWithTarget:self.centerManager.centerMnaager selector:@selector(connectPeripheral:options:) object:self.connectOptions];
}

- (void)dealDeviceConnectWithError:(NSError *)error deviceConnectType:(deviceConntType)deviceConnectType {
    _isReconnectDevice = NO;
    
    if (self.blueManagerConnectDeviceCallBack) {
        self.blueManagerConnectDeviceCallBack(self, error, deviceConnectType);
    }
}

#pragma mark -- CBPeripheralDelegate-----> update RSSI 值

//ios 8.0 的时候
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    //去掉警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    NSLog(@"读取RSSI===========%@  RSSI=====%@  error=======%@",peripheral.identifier,peripheral.RSSI,error);
    self.RSSI = peripheral.RSSI;
    if (self.blueManagerReadRSSICallBack) {
        self.blueManagerReadRSSICallBack(self, peripheral.RSSI, error);
    }
#pragma clang diagnostic pop
}

- (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error {
    NSLog(@"读取RSSI===========%@  RSSI=====%@  error=======%@",peripheral.identifier,RSSI,error);
    self.RSSI = RSSI;
    if (self.blueManagerReadRSSICallBack) {
        self.blueManagerReadRSSICallBack(self, RSSI, error);
    }
}

#pragma mark -- CBPeripheralDelegate ----> discover service

//发现服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    NSLog(@"device find service %@====== serviceArray===%@   error=======%@",peripheral.identifier,peripheral.services,error);
    
    for (CBService *tempService in peripheral.services) {
        GYService *temps = [self searchServiceWithService:tempService];
        //代表这个服务没有在这个设备服务数组中 属于新寻找到的新服务
        if (temps == nil) {
            GYService *service = [[GYService alloc] initWithService:tempService perpheral:self];
            [self.serviceArray addObject:service];
        }
    }
    
    //判断服务数组中
    if (self.findServiceCallBackArray.count > 0 ) {
        blueManagerSearchDeviceServiceBlock callback = self.findServiceCallBackArray.firstObject ;
        callback(self,self.serviceArray,nil);
        callback = nil ;
        
        [self.findServiceCallBackArray removeObjectAtIndex:0];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverIncludedServicesForService:(nonnull CBService *)service error:(nullable NSError *)error
{
    NSLog(@"已连接上行的设备发现了服务%@ serviceArray:%@ error:%@",peripheral.identifier,peripheral.services,error);
    
    NSAssert(NO, @"");
    
}

#pragma mark characteristic

//发现服务上的特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    NSLog(@"发现了服务上的特征 %@ characterArray:%@ error:%@",service.UUID,service.characteristics,error);
    
    GYService *tempService = [self searchServiceWithService:service];
    
    if (tempService) {
        [tempService dealDiscoverCharacteristic:service.characteristics error:error];
    }
    else{
        NSAssert(NO, @"you should deal this error");
    }
}


#pragma mark - write read notify operition

//监听Notify
//或则写入数据后,数据会在会在这个接口里面调用

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    GYService *tempService = [self searchServiceWithService:characteristic.service];
    //查找服务中的这个特征
    GYCharacteristic *tempCharacteristic = [tempService searchCharacteristciWithCharacteristic:characteristic];
    
    NSAssert(tempCharacteristic, @"attention ! this character is empty ."); //这个特征是空的
    
    if (tempCharacteristic.isNotifying) {
        
        NSLog(@"特征上的数据更新: %@ data:%@ error:%@",characteristic.UUID,characteristic.value ,error);
        [tempCharacteristic dealOperationCharacterWithType:operationTypeNotify error:error];
    }else {
        
        NSLog(@"读 特征的回调: %@ data:%@ error:%@",characteristic.UUID,characteristic.value ,error);
        
        [tempCharacteristic dealOperationCharacterWithType:operationTypeRead error:error];
    }
}

//当特征注册通知后,会回调这个方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"监听 特征的回调: %@ error:%@",characteristic.UUID ,error);
    
    if (characteristic.isNotifying) {
        
    }else {
        NSLog(@"Notification stopped on %@.  Disconnecting", characteristic);
    }
    
    GYService *tempService = [self searchServiceWithService:characteristic.service];
    GYCharacteristic *tempCharacteristic = [tempService searchCharacteristciWithCharacteristic:characteristic];
    
    NSAssert(tempCharacteristic, @"attention ! this character is empty .");
    
    [tempCharacteristic dealOperationCharacterWithType:operationTypeNotify error:error];
}

//当写入某个特征后,外设代理执行的回调
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"写 特征的回调: %@ error:%@",characteristic.UUID ,error);
    
    GYService *tempService = [self searchServiceWithService:characteristic.service];
    GYCharacteristic *tempCharacteristic = [tempService searchCharacteristciWithCharacteristic:characteristic];
    
    NSAssert(tempCharacteristic, @"attention ! this character is empty .");
    
    [tempCharacteristic dealOperationCharacterWithType:operationTypeWrite error:error];
}

- (void)peripheralDidUpdateName:(CBPeripheral *)peripheral
{
    NSLog(@"peripheralDidUpdateName");
}

//设置通知
-(void)notifyCharacteristic:(CBPeripheral *)peripheral
             characteristic:(CBCharacteristic *)characteristic{
    //设置通知，数据通知会进入：didUpdateValueForCharacteristic方法
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
    
}

//取消通知
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral
                   characteristic:(CBCharacteristic *)characteristic{
    
    [peripheral setNotifyValue:NO forCharacteristic:characteristic];
}

- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
    
    NSLog(@"didRetrievePeripherals%@\n%@\n",central,peripherals);
    
    int i = 0;
    for(CBPeripheral *peripheral in peripherals) {
        NSLog(@"%@",[NSString stringWithFormat:@"[%d] - peripheral : %@ with UUID : %@",i,peripheral,peripheral.identifier]);
        i++;
        //Do something on each known peripheral.
    }
    
}
- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
    NSLog(@"didRetrieveConnectedPeripherals:%@\n%@",peripherals,central);
    
    
    int i = 0;
    for(CBPeripheral *peripheral in peripherals) {
        i++;
        NSLog(@"%@",[NSString stringWithFormat:@"[%d] - peripheral : %@ with UUID : %@",i,peripheral,peripheral.identifier]);
        //Do something on each connected peripheral.
    }
    
}

- (void)peripheralDidInvalidateServices:(CBPeripheral *)peripheral
{
    NSLog(@"peripheralDidInvalidateServices  %@",peripheral);
}
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray *)invalidatedServices
{
    NSLog(@"didModifyServices%@ \n%@",invalidatedServices,peripheral);
}


#pragma Mark -- 懒加载

- (NSMutableArray *)serviceArray {
    if (!_serviceArray) {
        _serviceArray = [NSMutableArray array];
    }
    
    return _serviceArray;
}

- (NSMutableArray<blueManagerSearchDeviceServiceBlock> *)findServiceCallBackArray {
    if (!_findServiceCallBackArray) {
        _findServiceCallBackArray = [NSMutableArray array];
    }
    
    return _findServiceCallBackArray;
}







@end
